package QAD::File::Find;
#
# Author: JustinZhang <fgz@qad.com>
# Date:   2006-09-19
#
use strict;
use File::Spec::Functions qw(catfile);
require Exporter;

our @ISA       = qw(Exporter);
our $VERSION   = "1.0";
our @EXPORT    = qw(find);

sub find {
    my $file_pat         = $_[0];
    my $dirs_ref         = $_[1];
    my $exclude_dir_pat  = $_[2];
    my $no_recursive     = $_[3];

    my @files;
    my @dirs;

    foreach my $dir (@$dirs_ref) {
        if(-d $dir ) {
            opendir(DIR, $dir) or warn "Can't read directory due to: $!";
       
            while(my $entry = readdir(DIR)) {
                my $complete_path = catfile($dir, $entry);
                if($entry =~ /$file_pat/ && -f $complete_path) {
                    push @files, $complete_path;
                }
                elsif($entry ne '.' && $entry ne '..' && -d $complete_path) {
                    push @dirs, $complete_path
                     if(!defined($exclude_dir_pat)
                         || $entry !~ /$exclude_dir_pat/);
                }
            }
            closedir(DIR);
        }
    }

    if(!$no_recursive && @dirs) {
        my @list = find($file_pat, \@dirs, $exclude_dir_pat);
        foreach(@list) {
            push @files, $_;
        }
    }
    return @files;
}

1;
__END__

=head1 NAME

QAD::File::Find - find files by pattern under given directory recursively

=head1 SYNOPSIS

  use QAD::File::Find;
  my @files = find($file_pattern, $dirs_tosearch_ref, $sub_dirs_to_skip);
  print join "\n", @files;

=head1 DESCRIPTION

This module finds files under directories specified by a reference to array in
the third argument 

=head1 EXPORT

find

=head1 API SPEC

=head2 find

This function accepts three parameters. The third is optional. 

=over 2

=item $_[0] -
file name pattern to search expressed in regular expression

=item $_[1] -
reference to the array containing directories to search

=item $_[2] -
optional pattern of sub directories to skip

=item $_[3] -
optional flag to control whether find recursivly

=back

If directory is relative path, it's resolved against current directory.
This function will return the matched file list.

=head1 EXAMPLE

  use FindBin qw($Bin);
  use lib "$Bin";
  use QAD::File::Find;
  my @files = find('\.p$|\.i$', [qw(AT MFGConv SOD], '^CVS$|^SVN$');
  print join "\n", @files;

=head1 SEE ALSO

This module is more convenient than L<File::Find> module, but less flexible.
And it can be instructed to skip certain directories, which is useful when used
under version controlled local work space such as CVS, Subversion. 
See also L<find(1)>

=head1 AUTHOR

Justin Zhang, E<lt>fgz@qad.comE<gt>

=cut
